// Dwarf.Unmanaged.Serial.cpp : Defines the entry point for the console application.
//

#include "Dwarf.Unmanaged.Hybrid.h"

using namespace std;

// The settings for this dwarf.
static Settings* settings;

// Get settings from the command line.
static int getSettings(int argc, char** argv, Solver *dlasolver) 
{
    int error = 0;
    if (dlasolver->isRootThread) 
    {
        settings = new Settings();
        if (settings->init(argc,argv,dlasolver))    //Parse all arguments for dwarf.
        {            
            delete settings;
            error = 1;
        }

        dlasolver->size = dlasolver->msize;
    }    

    //Distribute error if that occurred while parsing.
    MPI_Bcast(&error, 1, MPI_INT, NUMBER_ROOT_PROCESS, MPI_COMM_WORLD);       

    if (error) return -1;

    //Distribute size of matrices.
    MPI_Bcast(&dlasolver->msize, 1, MPI_INT, NUMBER_ROOT_PROCESS, MPI_COMM_WORLD);

    //Init matrices.
    if (!dlasolver->isRootThread) 
    {
        dlasolver->rgrid = new double*[dlasolver->msize];
        for (int i = 0; i < dlasolver->msize; i ++) 
        {
            dlasolver->rgrid[i] = new double[dlasolver->msize];
        }

        dlasolver->lgrid = new double*[1];
        dlasolver->lgrid[0] = new double[dlasolver->msize];

        dlasolver->result = new double*[1];
        dlasolver->result[0] = new double[dlasolver->msize];
    }

    //Distribute right matrix to all.
    for (int i = 0; i < dlasolver->msize; i ++) 
    {
        MPI_Bcast(dlasolver->rgrid[i], dlasolver->msize, MPI_DOUBLE, NUMBER_ROOT_PROCESS, MPI_COMM_WORLD);
    }    

    //Compute size of arrays.
    dlasolver->size = dlasolver->isRootThread ? dlasolver->msize : 1;

    return 0;
}

// Point of the program start.
void main(int argc, char** argv)
{   

    Solver* dlasolver = new Solver(); 

    if (dlasolver->commSize == 1) 
    {
        delete dlasolver;
        printf("Only one mpi process.");
        exit(-1);
    }

    if (getSettings(argc, argv, dlasolver))         // Get settings from the command line.
    {
        delete dlasolver;
        exit(-1);
    }

    MPI_Barrier(MPI_COMM_WORLD);

    if (dlasolver->isRootThread) 
    {
        settings->start();                          // Start new time count.
    }

	dlasolver->solve();                             // Solve the current problem.

    MPI_Barrier(MPI_COMM_WORLD);

    if (dlasolver->isRootThread) 
    {
        settings->finish(dlasolver);                // Stop the time count and write results.
        delete settings;
    }

    delete dlasolver;
}
